package org.dyndns.opendemogroup.optimizer.selections;

import java.util.Random;

import org.dyndns.opendemogroup.optimizer.IOptimizationProblem;
import org.dyndns.opendemogroup.optimizer.ISelection;
import org.dyndns.opendemogroup.optimizer.Member;
import org.dyndns.opendemogroup.optimizer.Pair;
import org.dyndns.opendemogroup.optimizer.Population;

/**
 * <p>
 * A selection that does not use fitness, except to exclude a portion of the
 * population that's less fit, thereby implementing a sort of elitism that is
 * particularly useful for Evolution Strategies.
 * </p>
 * <p>
 * This implementation assumes the population has already been sorted.
 * </p>
 */
public class RandomElite implements ISelection
{

	private final int maxConsidered;

	/**
	 * Constructs a selection with the specified maximum number
	 * 
	 * @param maxConsidered
	 *        The maximum number of members to be considered. Setting this equal
	 *        to the population size will cause this class to behave like a
	 *        simple random selection.
	 */
	public RandomElite ( int maxConsidered )
	{
		this.maxConsidered = maxConsidered;
	}

	/**
	 * @see ISelection#reset(Random, Population, IOptimizationProblem)
	 */
	public void reset ( Random randomSource, Population population,
			IOptimizationProblem problem )
	{
		// does nothing on purpose
	}

	/**
	 * @see ISelection#select(Random, Population, IOptimizationProblem, int)
	 */
	public Pair<Member, Member> select ( Random randomSource,
			Population population, IOptimizationProblem problem, int loopIndex )
	{
		// { initialization
		final int popSize = population.getPopulationSize ( );
		final boolean isMaximizing = problem.isMaximizing ( );
		int max = maxConsidered;
		if ( max > popSize )
		{
			max = popSize;
		}
		Pair<Member, Member> result = new Pair<Member, Member> ( );
		// }

		int one = choose ( popSize, randomSource, max, isMaximizing );
		result.first = population.members[one];
		int two = choose ( popSize, randomSource, max, isMaximizing );
		result.second = population.members[two];

		return result;
	}

	static int choose ( int popSize, Random randomSource, int max,
			boolean isMaximizing )
	{
		int index = randomSource.nextInt ( max );
		if ( isMaximizing )
		{
			index = popSize - 1 - index;
		}
		return index;
	}

}
